#include "WidgetVariantMatrix.h"
#include "DefineCommon.h"
#include "EMatrix4x4.h"
#include "EVariant.h"
#include "ui_WidgetVariantMatrix.h"
#include <iostream>
#include <QMatrix4x4>
#include <QQuaternion>


WidgetVariantMatrix::WidgetVariantMatrix(QWidget *parent) :
    WidgetVariant(parent),
    ui(new Ui::WidgetVariantMatrix)
{
    ui->setupUi(this);
    ui->doubleSpinRX->setSingleStep(1.0);
    ui->doubleSpinRY->setSingleStep(1.0);
    ui->doubleSpinRZ->setSingleStep(1.0);
    ui->doubleSpinQW->setSingleStep(1.0);


    this->buildConnect();
    this->slotComoboxMode(ui->comboBoxMode->currentText());

}

WidgetVariantMatrix::~WidgetVariantMatrix()
{
    delete ui;
}

void WidgetVariantMatrix::refreshByProperty(EItemMetaPropertyPtr p)
{
    WidgetVariant::refreshByProperty(p);
    this->clearConnect();

    // ui->horizontalLayout_3
    EString text = p->nameCN.isEmpty() ? p->name : p->nameCN;
    if (text.left(3) == "ui_")
    {
        text.removeLeft(3);
    }
    p->getPropertyValue(p->value);

    ui->labelName->setText(text.data());

    //update value
    EMatrix4x4 mat = p->value.to_EMatrix4x4();

    EVec3 pos = mat.getTrans();
    
    ui->doubleSpinTransX->setValue(pos.x);
    ui->doubleSpinTransY->setValue(pos.y);
    ui->doubleSpinTransZ->setValue(pos.z);

    if(ui->comboBoxMode->currentText() == "Trans+Euler-XYZ")
    {
        EVec3 eulerAngle = mat.getEulerAngle();
        ui->doubleSpinRX->setValue(RADIUS_TO_DEGREE(eulerAngle.x));
        ui->doubleSpinRY->setValue(RADIUS_TO_DEGREE(eulerAngle.y));
        ui->doubleSpinRZ->setValue(RADIUS_TO_DEGREE(eulerAngle.z));
    }
    else if(ui->comboBoxMode->currentText() == "Trans+Quat")
    {
        EVec4 quat = mat.getQuat();
        ui->doubleSpinRX->setValue(quat.x);
        ui->doubleSpinRY->setValue(quat.y);
        ui->doubleSpinRZ->setValue(quat.z);
        ui->doubleSpinQW->setValue(quat.w);
    }
    else
    {
        ui->doubleSpinRX->setValue(0);
        ui->doubleSpinRY->setValue(0);
        ui->doubleSpinRZ->setValue(0);
        ui->doubleSpinQW->setValue(0);
    }


    if(p->additionalInfo.isEmpty())
    {
        // ui->comboBoxMode->setCurrentText("Trans+Euler-XYZ");
        // this->slotComoboxMode("Trans+Euler-XYZ");
    }
    else
    {
        // ui->comboBoxMode->setCurrentText(p->additionalInfo);
        // this->slotComoboxMode(p->additionalInfo);
    }

    ui->doubleSpinTransX->setEnabled(!p->ifReadOnly);
    ui->doubleSpinTransY->setEnabled(!p->ifReadOnly);
    ui->doubleSpinTransZ->setEnabled(!p->ifReadOnly);
    ui->doubleSpinRX->setEnabled(!p->ifReadOnly);
    ui->doubleSpinRY->setEnabled(!p->ifReadOnly);
    ui->doubleSpinRZ->setEnabled(!p->ifReadOnly);
    ui->doubleSpinQW->setEnabled(!p->ifReadOnly);

    //this->slotValueChanged(0);
    
    this->buildConnect();
}
    
void WidgetVariantMatrix::buildConnect()
{
    QObject::connect(ui->comboBoxMode, 
                     SIGNAL(currentIndexChanged(const QString&)),
                     this,
                     SLOT(slotComoboxMode(const QString&)));
    QObject::connect(ui->comboBoxFrame, 
                     SIGNAL(currentIndexChanged(const QString&)),
                     this,
                     SLOT(slotComoboxFrame(const QString&)));
    QList<QWidget*> spinList;
    spinList<<ui->doubleSpinTransX
            <<ui->doubleSpinTransY
            <<ui->doubleSpinTransZ
            <<ui->doubleSpinRX
            <<ui->doubleSpinRY
            <<ui->doubleSpinRZ
            <<ui->doubleSpinQW;
    for(int i = 0 ; i < spinList.size(); i++)
    {
        QObject::connect(spinList[i],
                         SIGNAL(valueChanged(double )),
                         this,
                         SLOT(slotValueChanged(double)));
    }

}

void WidgetVariantMatrix::clearConnect()
{
    QObject::disconnect(ui->comboBoxMode, 
                     SIGNAL(currentIndexChanged(const QString&)),
                     this,
                     SLOT(slotComoboxMode(const QString&)));
    QObject::disconnect(ui->comboBoxFrame, 
                     SIGNAL(currentIndexChanged(const QString&)),
                     this,
                     SLOT(slotComoboxFrame(const QString&)));
    QList<QWidget*> spinList;
    spinList<<ui->doubleSpinTransX
            <<ui->doubleSpinTransY
            <<ui->doubleSpinTransZ
            <<ui->doubleSpinRX
            <<ui->doubleSpinRY
            <<ui->doubleSpinRZ
            <<ui->doubleSpinQW;
    for(int i = 0 ; i < spinList.size(); i++)
    {
        QObject::disconnect(spinList[i],
                         SIGNAL(valueChanged(double )),
                         this,
                         SLOT(slotValueChanged(double)));
    }

}

void WidgetVariantMatrix::getTransXYZ(double& x, double& y, double& z)
{
    x = ui->doubleSpinTransX->value();
    y = ui->doubleSpinTransY->value();
    z = ui->doubleSpinTransZ->value();
}

void WidgetVariantMatrix::setTransXYZ(double x, double y, double z)
{
    ui->doubleSpinTransX->setValue(x);
    ui->doubleSpinTransY->setValue(y);
    ui->doubleSpinTransZ->setValue(z);
}

void WidgetVariantMatrix::setRotateXYZW(double rx, double ry, double rz, double w)
{
    ui->doubleSpinRX->setValue(rx);
    ui->doubleSpinRY->setValue(ry);
    ui->doubleSpinRZ->setValue(rz);
    ui->doubleSpinQW->setValue(w);
}

void WidgetVariantMatrix::setMode(const QString& mode)
{
    ui->comboBoxMode->setCurrentText(mode);
}

void WidgetVariantMatrix::slotComoboxMode(const QString& text)
{
    if(text == "Trans+Quat")
    {
        ui->labelQuatWName->setVisible(true);
        ui->doubleSpinQW->setVisible(true);
        ui->labelRotateName->setText("Quat");
    }
    else 
    {
        ui->labelQuatWName->setVisible(false);
        ui->doubleSpinQW->setVisible(false);
        QString temp = text;
        temp = temp.remove(0, 6);
        ui->labelRotateName->setText(temp);
    }

    if(this->m_property == nullptr)
    {
        return;
    }

    this->refreshByProperty(this->m_property);
}

void WidgetVariantMatrix::slotComoboxFrame(const QString& text)
{
    // std::cout<<"WidgetVariantMatrix::slotComoboxFrame,text="<<text.toStdString()<<"\n";
}

void WidgetVariantMatrix::slotValueChanged(double value)
{
    // std::cout<<"WidgetVariantMatrix::slotDoublespin,value="<<value<<"\n";
    if (m_property == nullptr)
    {
        return;
    }

    //QMatrix4x4 m;
    EMatrix4x4 m;

    //Trans+Euler-XYZ
    //Trans+Quat
    double x = ui->doubleSpinTransX->value();
    double y = ui->doubleSpinTransY->value();
    double z = ui->doubleSpinTransZ->value();
    double rx = ui->doubleSpinRX->value();
    double ry = ui->doubleSpinRY->value();
    double rz = ui->doubleSpinRZ->value();
    double rw = ui->doubleSpinQW->value();

    if(ui->comboBoxMode->currentText() == "Trans+Quat")
    {
        EVec4 quat;
        quat.x = rx;
        quat.y = ry;
        quat.z = rz;
        quat.w = rw;
        m.makeRotate(quat);

        m.setTranslate(x,y,z);

        EVariant varOld = this->m_property->value;
        
		EVariant var(m);
		this->m_property->setPropertyValue(var);

        emit signalVariantChanged(m_property, varOld);
    }
    else if(ui->comboBoxMode->currentText() == "Trans+Euler-XYZ") 
    {
        //using qt's quat to convert euler angle to quat
        // QQuaternion quat = QQuaternion::fromEulerAngles(rx,ry,rz);
        // QVector4D qvec = quat.toVector4D();
        // using EMatrix4x4 and EVec4 to convert euler angle
        EVec4 quat;
        quat.makeRotate(DEGREE_TO_RADIUS(rx), EVec3(1,0,0),
                DEGREE_TO_RADIUS(ry), EVec3(0,1,0),
                DEGREE_TO_RADIUS(rz), EVec3(0,0,1));
        m.makeRotate(quat);

        m.setTranslate(x,y,z);

        EVariant varOld = this->m_property->value;
        
		EVariant var(m);
		this->m_property->setPropertyValue(var);

        // m_property->value = m;
        emit signalVariantChanged(m_property, varOld);
    }
}
        //使用glm进行矩阵计算，但是发现用法太复杂
        // glm::quat q(rw, rx, ry, rz);
        // glm::mat4 mm = glm::mat4_cast(q);
        // mm = glm::translate(mm, glm::vec3(x,y,z));
        // float* data = glm::value_ptr(mm);
        // m = QMatrix4x4(data);
//         m(3,0) = x;
//         m(3,1) = y;
//         m(3,2) = z;
// 
//         m(2,0) = rx;
//         m(2,1) = ry;
//         m(2,2) = rz;
//         m(2,3) = rw;
